Typy ogólne

kowariancja tablic, typy ogólne, funkcje, konsumenci, itp.


dr inż. Aleksander Smywiński-Pohl

apohllo@agh.edu.pl

http://apohllo.pl/dydaktyka/programowanie-obiektowe

konsultacje: wtorek 15:30 - 18:00, pokój 4.61

Pytanie 1

Czy refleksja w Javie będzie nadal działać po zastosowaniu zaciemniania kodu?

Pytanie 2

Czy trudność w szukaniu błędów jest jedynym powodem dla którego odradza się używania mechanizmu refleksji?

Typ ogólny (generyczny, parametryzowany)

In [1]:
class SingletonContainer<E> {
    private E element;
    
    public void put(E element){
        this.element = element;
    }
    
    public E get(){
        return element;
    }
}
In [2]:
SingletonContainer<String> container = new SingletonContainer<>();
container.put("Ala");
String string = container.get();
System.out.println(string);
Ala
In [3]:
SingletonContainer<Integer> container = new SingletonContainer<>();
container.put(1);
Integer integer = container.get();
System.out.println(integer);
1

Kowariancja tablic

In [4]:
class ArrayRuntimeError {
  public static void main(String[] args){
    String words[] = {"Ala", "ma", "kota"};
    Object[] objects = words;
    objects[0] = new Integer(1);
  }
}
In [5]:
String[] args = {};
ArrayRuntimeError.main(args);
---------------------------------------------------------------------------
java.lang.ArrayStoreException: java.lang.Integer
	at ArrayRuntimeError.main(#24:5)
	at .(#26:1)

Kowariancja list

In [6]:
import java.util.*;

class ListCompilationError {
  public static void main(String[] args){
    List<String> words = Arrays.asList("Ala", "ma", "kota");
    List<Object> objects = words;

    objects.add(0,new Integer(1));
  }
}
|       List<Object> objects = words;
incompatible types: java.util.List<java.lang.String> cannot be converted to java.util.List<java.lang.Object>
In [10]:
class ListGenericError {
  public static void main(String[] args){
    List<String> words = Arrays.asList("Ala", "ma", "kota");
    List<?> objects = words;

    String string = objects.get(0);
    objects.add(0,"Jola");
  }
}
|       String string = objects.get(0);
incompatible types: capture#4 of ? cannot be converted to java.lang.String

|       objects.add(0,"Jola");
incompatible types: java.lang.String cannot be converted to capture#5 of ?
In [13]:
import java.util.*;

class ListGenerics {
  public static void main(String[] args){
    List<String> words = Arrays.asList("Ala", "ma", "kota");
    List<? extends String> objects = words;

    String string = objects.get(0);
    objects.add(0,"Jola");
  }
}

//String[] args = {};
//ListGenerics.main(args);
|       objects.add(0,"Jola");
incompatible types: java.lang.String cannot be converted to capture#6 of ? extends java.lang.String

? extends vs ? super

In [ ]:
List<? extends Object> objects;

List<? super String> strings;

  • ? extends y => (czytaj) ? extends y
  • ? super y => (czytaj) ? isSuperOf y

Interfejs java.util.function.Consumer<T>

  • void accept(T t)
  • default Consumer<T> andThen(Consumer<? super T> after)
In [20]:
import java.util.function.Consumer;

Consumer<Integer> integerConsumer;
Consumer<Number> numberConsumer;
Consumer<Object> objectConsumer;
In [22]:
class Example {
    public static void exampleMethod() {
        numberConsumer.andThen(numberConsumer);
    }
}
In [23]:
class Example {
    public static void exampleMethod() {
        integerConsumer.andThen(numberConsumer);
    }
}
In [24]:
class Example {
    public static void exampleMethod() {
        numberConsumer.andThen(integerConsumer);
    }
}
|           numberConsumer.andThen(integerConsumer);
incompatible types: java.util.function.Consumer<java.lang.Integer> cannot be converted to java.util.function.Consumer<? super java.lang.Number>
In [19]:
class Example {
    public static void exampleMethod() {
        numberConsumer.andThen(objectConsumer);
    }
}
In [ ]:
class Example {
    public static void exampleMethod() {
        integerConsumer.andThen(objectConsumer);
    }
}
In [27]:
import java.util.stream.*;
import java.util.function.*;

//       vvvvvvv
Consumer<Integer> addOne = x -> {      
    System.out.print("Dodaj jeden: "); 
    System.out.println(1 + x); 
};

//       vvvvvv
Consumer<Object> printTwice = x -> {
    System.out.print("Wypisz dwa razy: "); 
    System.out.print(x + " "); 
    System.out.println(x);
};

Consumer<Object> combined = printTwice.andThen(addOne);

Arrays.asList(1,2,3,4,5,6,7,8,9,10).stream().forEach(combined);
|   Consumer<Object> combined = printTwice.andThen(addOne);
incompatible types: java.util.function.Consumer<java.lang.Integer> cannot be converted to java.util.function.Consumer<? super java.lang.Object>

Interfejs java.util.function.Function<T,R>

In [ ]:
R apply(T t)
default <V> Function<T,V> andThen(Function<? super R,? extends V> after)
default <V> Function<V,R> compose(Function<? super V,? extends T> before)
static <T> Function<T,T> identity()
In [28]:
import java.util.function.Function;

Function<Integer,Integer> intIntFunction = (x) -> x * 2;
Function<Number,String> numStrFunction = (x) -> x.toString();
Function<Object,Integer> objIntFunction = (x) -> x.toString().length();
In [29]:
Function<Integer, Object> combined = intIntFunction.andThen(numStrFunction);
In [ ]:
T = Integer
R = Integer     // -> ?=Number isSuperOf R=Integer 
V = Object      // -> ?=String extends V=Object
In [30]:
import java.util.stream.*;
import java.util.function.*;

Function<Integer,Integer> intIntFunction = (x) -> x * 2;
Function<Number,String> numStrFunction = (x) -> "" + x.toString().length();

Function<Integer, Object> combined = intIntFunction.andThen(numStrFunction);

Arrays.asList(1,2,3,4,5,6,7,8,9,10).stream().map(combined).
    collect(Collectors.toList());
Out[30]:
[1, 1, 1, 1, 2, 2, 2, 2, 2, 2]

Wymazywanie typu

In [32]:
class TypeErasure {
    public void consume(List<Integer> integers){
    }
    
    public void consume(List<String> strings){
    }
}
|       public void consume(List<String> strings){
|       }
name clash: consume(java.util.List<java.lang.String>) and consume(java.util.List<java.lang.Integer>) have the same erasure

Pytania?